package com.mazaiting.classpath;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.Optional;

/**
 * 类路径
 *
 * @author mazaiting
 * @since 2021/8/10
 */
@Slf4j
@Data
public class Classpath {
    /**
     * 启动类路径
     */
    private Entry bootClasspath;
    /**
     * 扩展类路径
     */
    private Entry extClasspath;
    /**
     * 用户类路径
     */
    private Entry userClasspath;

    public Classpath(String jreOption, String cpOption) {
        parseBootAndExtClasspath(jreOption);
        parseUserClasspath(cpOption);
    }

    /**
     * 解析用户类路径
     * 如果用户没有提供-classpath/-cp选项，则使用当前目录作为用户类路径
     * @param cpOption 用户类路径
     */
    private void parseUserClasspath(String cpOption) {
        if (ObjectUtil.isEmpty(cpOption)) {
            cpOption = ".";
        }
        this.userClasspath = EntryFactory.newEntry(cpOption);
    }

    /**
     * 解析启动类与扩展类路径
     * @param jreOption jre参数
     */
    private void parseBootAndExtClasspath(String jreOption) {
        Optional<String> jreDirOpt = getJreDir(jreOption);
        if (!jreDirOpt.isPresent()) return;
        String jreDir = jreDirOpt.get();
        // 解析 jre/lib/*
        File jreLibPath = FileUtil.file(jreDir, "lib", "*");
        this.bootClasspath = EntryFactory.newEntry(jreLibPath.getPath());
        // 解析 jre/lib/ext/*
        File jreExtPath = FileUtil.file(jreDir, "lib", "ext", "*");
        this.extClasspath = EntryFactory.newEntry(jreExtPath.getPath());
    }

    /**
     * 获取 JRE 路径
     * 优先使用用户输入的-Xjre选项作为jre目录。
     * 如果没有输入该 选项，则在当前目录下寻找jre目录。
     * 如果找不到，尝试使用 JAVA_HOME 环境变量
     * @param jreOption jre参数
     * @return jre 路径
     */
    private Optional<String> getJreDir(String jreOption) {
        // 优先使用用户输入的-Xjre选项作为jre目录
        if (ObjectUtil.isNotEmpty(jreOption) && FileUtil.exist(jreOption)) {
            return Optional.ofNullable(jreOption);
        }
        String currentJre = "./jre";
        // 在当前目录下寻找jre目录
        if (FileUtil.exist(currentJre)) {
            return Optional.of(currentJre);
        }
        // 尝试使用 JAVA_HOME环境变量
        String javaHome = System.getenv().get("JAVA_HOME");
        if (ObjectUtil.isNotEmpty(javaHome)) {
            return Optional.of(FileUtil.file(javaHome, "jre").getPath());
        }
        log.error("Can not find jre folder!");
        return Optional.empty();
    }

    //func (self *Classpath) ReadClass(className string) ([]byte, Entry, error) {...} func (self *Classpath) String() string {...}

    /**
     * 根据类名读取类的二进制数据
     * 传递给ReadClass（）方法的类名不包含“.class”后缀
     * @param className 类名
     * @return 类响应
     */
    public ClassResponse readClass(String className) {
        className = className + ".class";
        // 启动类读取
        ClassResponse classResponse = this.bootClasspath.readClass(className);
        if (ObjectUtil.isEmpty(classResponse.getError())) return classResponse;
        // 扩展类读取
        classResponse = this.extClasspath.readClass(className);
        if (ObjectUtil.isEmpty(classResponse.getError())) return classResponse;
        // 用户类读取
        return this.userClasspath.readClass(className);
    }

    @Override
    public String toString() {
        return this.userClasspath.toString();
    }
}


















